package com.whmall.service.crm.module.companycertificatechemical.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.text.StrBuilder;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.whmall.common.enumeration.VerifyEnum;
import com.whmall.component.entity.dto.OperatorReqDTO;
import com.whmall.component.enumeration.OperatorTypeEnum;
import com.whmall.component.service.AbstractDbService;
import com.whmall.service.crm.entity.dto.companycertificatechemical.*;
import com.whmall.service.crm.module.company.dao.CompanyMapper;
import com.whmall.service.crm.module.company.entity.CompanyDO;
import com.whmall.service.crm.module.companybusinesscertificate.dao.CompanyBusinessCertificateMapper;
import com.whmall.service.crm.module.companybusinesscertificate.entity.CompanyBusinessCertificateDO;
import com.whmall.service.crm.module.companybusinesscertificate.entity.qo.CompanyBusinessCertificateQO;
import com.whmall.service.crm.module.companybusinesscertificate.enumeration.BusinessCertificateTypeEnum;
import com.whmall.service.crm.module.companycertificatechemical.CompanyCertificateChemicalApproveQueryCriteria;
import com.whmall.service.crm.module.companycertificatechemical.CompanyCertificateChemicalService;
import com.whmall.service.crm.module.companycertificatechemical.entity.CompanyCertificateChemicalApproveDO;
import com.whmall.service.crm.module.companycertificatechemical.entity.CompanyCertificateChemicalDO;
import com.whmall.service.crm.module.companycertificatechemical.entity.qo.CompanyCertificateChemicalQO;
import com.whmall.service.crm.module.companycertificatechemical.enumeration.ApproveStatusEnum;
import com.whmall.service.crm.module.companycertificatechemical.enumeration.AssociateChemicalResultEnum;
import com.whmall.service.crm.module.companycertificatechemical.impl.dao.CompanyCertificateChemicalApproveMapper;
import com.whmall.service.crm.module.companycertificatechemical.impl.dao.CompanyCertificateChemicalMapper;
import lombok.RequiredArgsConstructor;
import lombok.Value;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * CompanyCertificateChemicalServiceImpl
 *
 * @author alex
 * @since 2020/8/17
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class CompanyCertificateChemicalServiceImpl extends AbstractDbService<CompanyCertificateChemicalMapper, CompanyCertificateChemicalDO> implements CompanyCertificateChemicalService {

    private final CompanyBusinessCertificateMapper certificateMapper;
    private final CompanyCertificateChemicalMapper associateMapper;
    private final CompanyCertificateChemicalApproveMapper approveMapper;
    private final CompanyCertificateChemicalApproveGenerator approveGenerator;

    private final CompanyMapper companyMapper;


    @Transactional
    @Override
    public List<AssociateChemicalResultRspDTO> associateChemicals(OperatorReqDTO operator, Long companyId, Long certificateId, Long bindToUserId,
                                                                  List<AssociateChemicalReqDTO> associateRequests,
                                                                  List<AssociateChemicalDetectResultReqDTO> associateChemicalDetectResults) {

        Assert.notNull(operator, "operator不能为空");
        Assert.notNull(operator.getOperatorId(), "operatorId不能为空");
        Assert.notNull(operator.getOperatorType(), "operatorType不能为空");
        Assert.notNull(companyId, "companyId不能为空");
        Assert.notNull(certificateId, "certificateId不能为空");
        Assert.notNull(bindToUserId, "bindToUserId不能为空");
        Assert.notNull(associateRequests, "associateRequests不能为空");
        Assert.notNull(associateChemicalDetectResults, "associateRequests不能为空");

        if (associateRequests.isEmpty()) {
            return Collections.emptyList();
        }

        List<AssociateChemicalResultRspDTO> results = associateRequests.stream()
                .map(e -> {
                    AssociateChemicalResultRspDTO dto = new AssociateChemicalResultRspDTO();
                    dto.setCas(e.getCas());
                    dto.setName(e.getName());
                    dto.setNameEn(e.getNameEn());
                    dto.setResult(AssociateChemicalResultEnum.CONTACT_SERVICE);
                    return dto;
                })
                .collect(Collectors.toList());

        Date now = new Date();
        List<CompanyCertificateChemicalDO> insertAssociates =
                applyResultsAsChemicalIds(companyId, certificateId, associateChemicalDetectResults, results)
                        .stream()
                        .map(e -> {
                            CompanyCertificateChemicalDO insert = new CompanyCertificateChemicalDO();
                            insert.setCompanyId(companyId);
                            insert.setCertificateId(certificateId);
                            insert.setUserId(bindToUserId);
                            insert.setCreateType(operator.getOperatorType().getValue());
                            insert.setCreateId(operator.getOperatorId());
                            insert.setCreateTime(now);
                            insert.setChemicalId(e);
                            return insert;
                        })
                        .collect(Collectors.toList());

        insertAssociates(insertAssociates);

        revalidateCertificateApproveData(certificateId);

        return results;
    }

    @Transactional
    @Override
    public CompanyCertificateChemicalRspDTO removeChemical(OperatorReqDTO operator, Long companyId, Long certificateId, Long associatedId) {
        Assert.notNull(operator, "operator不能为空");
        Assert.notNull(operator.getOperatorId(), "operatorId不能为空");
        Assert.notNull(operator.getOperatorType(), "operatorType不能为空");
        CompanyCertificateChemicalDO associated = associateMapper.getById(associatedId);
        if (null == associated) {
            throw new IllegalArgumentException("关联ID不存在");
        }

        if (!associated.getCompanyId().equals(companyId)
                || !associated.getCertificateId().equals(certificateId)) {
            throw new IllegalArgumentException("关联ID不存在");
        }

        CompanyCertificateChemicalDO update = new CompanyCertificateChemicalDO();
        update.setId(associatedId);
        update.setDeleted((int) (System.currentTimeMillis() / 1000));

        //
        // 操作人
        update.setUpdateType(operator.getOperatorType().getValue());
        update.setUpdateId(operator.getOperatorId());
        update.setUpdateTime(new Date());

        //
        // 软删除
        associateMapper.updateByIdSelective(update);
        revalidateCertificateApproveData(certificateId);
        return do2Dto(associated, CompanyCertificateChemicalRspDTO.class);
    }

    @Transactional
    @Override
    public void deleteAllApproveList() {
        log.warn("开始删除所有的证照审批数据");
        int count = approveMapper.deleteAll();
        log.warn("已删除所有的证照审批数据，共 [{}] 条", count);
    }

    @Transactional
    @Override
    public void rebuildAllApproveFromAssociated() {
        List<Long> certificateIds = associateMapper.listAllCertificateId();

        log.warn("开始生成所有的证照审批数据");

        //
        // 每次生成10个证照的审批
        final int chunkSize = 10;
        final AtomicInteger counter = new AtomicInteger();
        final AtomicInteger inserted = new AtomicInteger();
        certificateIds.stream()
                .collect(Collectors.groupingBy(e -> counter.getAndIncrement() / chunkSize))
                .values()
                .parallelStream()
                .forEach(e -> approveGenerator.generateFromAssociatedCertificateIds(e)
                        .stream()
                        .peek(i -> log.debug("开始生成公司 [{}] 的证照 [{}] 审批数据", i.getCompanyId(), i.getId()))
                        .forEach(i -> {
                            this.approveMapper.insertSelective(i);
                            inserted.incrementAndGet();
                        }));

        log.warn("已生成所有的证照审批数据，共 [{}] 条数据", inserted.get());
    }

    @Transactional
    @Override
    public List<CompanyCertificateChemicalRspDTO> approval(Long requesterId, Long companyId, Long certificateId, ApprovalCertificateChemicalReqDTO request) {
        Assert.notNull(requesterId, "审批人不能为null");
        Assert.notNull(request, "审批请求不能为null");

        if (request.getAssociateIds().isEmpty()) {
            throw new IllegalArgumentException("审批证照化合物关联ID列表不能为空");
        }

        final Date now = new Date();
        List<CompanyCertificateChemicalDO> certificateChemicalDOS = associateMapper.listByIds(request.getAssociateIds())
                .stream()
                //
                // 剔除跟公司以及证照ID不匹配的关联
                .filter(e -> e.getCompanyId().equals(companyId) && e.getCertificateId().equals(certificateId))
                .peek(e -> {
                    if (ApproveStatusEnum.fromValue(e.getVerified()) != ApproveStatusEnum.REVIEW) {
                        throw new IllegalArgumentException("证照化合物关联当前不是待审核状态: " + e.getId());
                    }

                    CompanyCertificateChemicalDO update = new CompanyCertificateChemicalDO();
                    update.setId(e.getId());
                    update.setVerified(request.isPass()
                            ? ApproveStatusEnum.PASSED.getValue()
                            : ApproveStatusEnum.REJECTED.getValue());
                    update.setVerifyId(requesterId);
                    update.setVerifyTime(now);
                    update.setNotPassCause(request.getNotPassCause());
                    if (update.getVerified().equals(ApproveStatusEnum.REJECTED.getValue())) {
                        update.setIsEffective((int) ((System.currentTimeMillis() / 1000) + e.getId()));
                    }
                    associateMapper.updateByIdSelective(update);
                }).collect(Collectors.toList());
        revalidateCertificateApproveData(certificateId);
        return do2Dto(certificateChemicalDOS, CompanyCertificateChemicalRspDTO.class);
    }

    @Override
    public int countBy(CompanyCertificateChemicalQueryReqDTO queryReqDTO) {
        CompanyCertificateChemicalQO qo = new CompanyCertificateChemicalQO();
        BeanUtils.copyProperties(queryReqDTO, qo);
        return associateMapper.countBy(qo);
    }

    @Override
    public List<CompanyCertificateChemicalStatisticDTO> statisticBy(CompanyCertificateChemicalQueryReqDTO queryReqDTO) {
        CompanyCertificateChemicalQO qo = new CompanyCertificateChemicalQO();
        BeanUtils.copyProperties(queryReqDTO, qo);
        List<CompanyCertificateChemicalStatisticDTO> list = associateMapper.countGroupByCompany(qo);
        if (CollUtil.isEmpty(list)) {
            return Collections.emptyList();
        }

        return list;
    }

    @Override
    public List<CompanyCertificateChemicalRspDTO> selectBy(CompanyCertificateChemicalQueryReqDTO queryReqDTO) {
        CompanyCertificateChemicalQO qo = new CompanyCertificateChemicalQO();
        BeanUtils.copyProperties(queryReqDTO, qo);
        if (CollUtil.isEmpty(qo.getChemicalIds())) {
            return new ArrayList<>();
        }
        return associateMapper.listBy(qo).stream().map(e -> {
            CompanyCertificateChemicalRspDTO rspDTO = new CompanyCertificateChemicalRspDTO();
            BeanUtils.copyProperties(e, rspDTO);
            return rspDTO;
        }).collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer certificate(CompanyCertificateChemicalOptionDTO option) {
        this.addSelf(option);
        // 新增审核信息
        List<CompanyCertificateChemicalApproveDO> approves = approveMapper.listByQueryCriteria
                (CompanyCertificateChemicalApproveQueryCriteria.builder()
                        .companyId(option.getCompanyId())
                        .certificateType(option.getBizCertificateTypeEnum())
                        .build());
        log.debug("增加公司关联化合物，公司ID：{}，证件类型：{}，查询结果数目：{}", option.getCompanyId(), option.getBizCertificateTypeEnum().getName(), approves.size());
        if (approves.isEmpty()) {
            CompanyCertificateChemicalApproveDO approve = new CompanyCertificateChemicalApproveDO();
            approve.setId(option.getCertificateId());
            approve.setCertificateType(option.getBizCertificateTypeEnum().getValue());
            approve.setCompanyId(option.getCompanyId());
            approve.setVerifiedList(",1,");
            approve.setChemicalIdList("," + option.getChemicalId().toString() + ",");
            log.debug("新增：{}", approve);
            approveMapper.insertSelective(approve);
        } else {
            CompanyCertificateChemicalApproveDO approve = approves.get(0);
            approve.setChemicalIdList(Optional.ofNullable(approve.getChemicalIdList()).orElse(",") + option.getChemicalId() + ",");
            log.debug("修改：{}", approve);
            approveMapper.updateById(approve);
        }
        return 1;
    }

    @Override
    public String certificates(List<CompanyCertificateChemicalOptionDTO> options) {
        Assert.notEmpty(options, "参数异常");


        // 保留的ID
        List<Long> companyIds = options.stream().map(CompanyCertificateChemicalOptionDTO::getCompanyId)
                .distinct()
                .collect(Collectors.toList());

        log.debug("全部的公司：{}", CollUtil.join(companyIds, ","));

        // 公司的全部证照信息
        Map<Long, List<CompanyCertificateChemicalDO>> companyCertificateChemicalMap = associateMapper.selectList(
                        new LambdaUpdateWrapper<>(CompanyCertificateChemicalDO.class)
                                .eq(CompanyCertificateChemicalDO::getDeleted, 0)
                                .in(CompanyCertificateChemicalDO::getCompanyId, companyIds)
                                .eq(CompanyCertificateChemicalDO::getChemicalId, options.get(0).getChemicalId()))
                .stream().collect(Collectors.groupingBy(CompanyCertificateChemicalDO::getCompanyId));


        StrBuilder strBuilder = new StrBuilder();

        Map<Long, List<CompanyCertificateChemicalOptionDTO>> companyOptionMap = options.stream()
                .collect(Collectors.groupingBy(CompanyCertificateChemicalOptionDTO::getCompanyId));

        for (Long companyId : companyIds) {

            // 现在要的
            List<CompanyCertificateChemicalOptionDTO> list = companyOptionMap.get(companyId);

            log.debug("开始处理：【{}】，共有【{}】个证照", companyId, list.size());

            if (CollUtil.isEmpty(list)) {
                continue;
            }


            // 这个公司的全部证照
            Map<Long, CompanyCertificateChemicalDO> companyCertificateChemicalsMap = companyCertificateChemicalMap
                    .getOrDefault(companyId, new ArrayList<>()).stream()
                    .collect(Collectors.toMap(CompanyCertificateChemicalDO::getCertificateId, e -> e, (a, b) -> b));

            // 当前关联的全部证照
            Set<Long> currentIds = companyCertificateChemicalsMap.values().stream().map(CompanyCertificateChemicalDO::getCertificateId)
                    .collect(Collectors.toSet());
            // 要处理的全部证照
            Map<Long, CompanyCertificateChemicalOptionDTO> listMap = list.stream()
                    .collect(Collectors.toMap(CompanyCertificateChemicalOptionDTO::getCertificateId, e -> e, (a, b) -> b));


            // 准备删除的
            Set<Long> preDeletes = list.stream()
                    .filter(e -> !e.getSelect())
                    .map(CompanyCertificateChemicalOptionDTO::getCertificateId)
                    .collect(Collectors.toSet());

            log.debug("准备删除：{}", CollUtil.join(preDeletes, ","));

            // 新增的证照
            Set<Long> adds = list.stream()
                    .filter(CompanyCertificateChemicalOptionDTO::getSelect)
                    .map(CompanyCertificateChemicalOptionDTO::getCertificateId)
                    .filter(e -> !currentIds.contains(e))
                    .collect(Collectors.toSet());
            log.debug("新增的证照：{}", CollUtil.join(adds, ","));
            // 要删除的证照
            List<Long> deletes = currentIds.stream().filter(preDeletes::contains)
                    .collect(Collectors.toList());
            log.debug("要删除的证照：{}", CollUtil.join(deletes, ","));


            // 发生变化的证照
            List<Long> updates = new ArrayList<>(CollUtil.unionDistinct(adds, deletes));
            log.debug("发生变化的证照：{}", CollUtil.join(updates, ","));
            if (updates.isEmpty()) {
                continue;
            }

            adds.stream().map(listMap::get).forEach(this::addSelf);
            CompanyCertificateChemicalOptionDTO one = options.get(0);
            deletes.forEach(e -> {
                CompanyCertificateChemicalDO companyCertificateChemicalDO = companyCertificateChemicalsMap.get(e);
                if (companyCertificateChemicalDO == null) {
                    return;
                }
                CompanyCertificateChemicalDO update = new CompanyCertificateChemicalDO();
                update.setId(companyCertificateChemicalDO.getId());
                update.setDeleted((int) (System.currentTimeMillis() / 1000));

                //
                // 操作人
                update.setUpdateType(OperatorTypeEnum.EMPLOYEE.getValue());
                update.setUpdateId(one.getOperationId());
                update.setUpdateTime(new Date());

                //
                // 软删除
                associateMapper.updateByIdSelective(update);


            });

            // 删除审批数据
            updates.forEach(approveMapper::deleteById);

            // 重新生成证照审批数据
            approveGenerator.generateFromAssociatedCertificateIds(updates);

            // 记录日志
            Map<Long, CompanyBusinessCertificateDO> certificateMap = certificateMapper.listBy(CompanyBusinessCertificateQO.builder()
                            .idIn(updates).build())
                    .stream().collect(Collectors.toMap(CompanyBusinessCertificateDO::getId, e -> e));

            Map<Long, CompanyDO> companyMap = companyMapper.getByIds(certificateMap.values().stream().map(CompanyBusinessCertificateDO::getCompanyId)
                            .distinct().collect(Collectors.toList()))
                    .stream().collect(Collectors.toMap(CompanyDO::getId, e -> e));

            adds.stream()
                    .map(listMap::get)
                    .filter(Objects::nonNull)
                    .forEach(e -> strBuilder.append(buildLog(e, certificateMap, companyMap, "关联")));
            deletes.stream()
                    .map(listMap::get)
                    .filter(Objects::nonNull)
                    .forEach(e -> strBuilder.append(buildLog(e, certificateMap, companyMap, "取消关联")));

        }


        return strBuilder.toString();
    }

    private String buildLog(
            CompanyCertificateChemicalOptionDTO e,
            Map<Long, CompanyBusinessCertificateDO> certificateMap,
            Map<Long, CompanyDO> companyMap,
            String type) {
        return StrUtil.format(
                "{}了【{}】的证件，" +
                        "证件类型：{}；" +
                        "证件编号：{}；" +
                        "有效期：{}。\n",
                type,
                Optional.ofNullable(companyMap.get(e.getCompanyId())).map(CompanyDO::getName).orElse(""),
                Optional.ofNullable(certificateMap.get(e.getCertificateId()))
                        .map(CompanyBusinessCertificateDO::getCertificateType)
                        .map(BusinessCertificateTypeEnum::fromValue)
                        .map(BusinessCertificateTypeEnum::getName)
                        .orElse(""),
                Optional.ofNullable(certificateMap.get(e.getCertificateId()))
                        .map(CompanyBusinessCertificateDO::getCertificateNumber)
                        .orElse(""),
                Optional.ofNullable(certificateMap.get(e.getCertificateId()))
                        .map(x -> DateUtil.format(x.getEffectiveStartDate(), "yyyy-MM-dd") +
                                "~" +
                                DateUtil.format(x.getEffectiveStartDate(), "yyyy-MM-dd"))
                        .orElse(""));
    }

    private void addSelf(CompanyCertificateChemicalOptionDTO option) {
        CompanyCertificateChemicalDO ccc = new CompanyCertificateChemicalDO();
        Date now = new Date();
        ccc.setDeleted(0);
        ccc.setIsEffective(1);
        ccc.setChemicalId(option.getChemicalId());
        ccc.setCertificateId(option.getCertificateId());
        ccc.setCompanyId(option.getCompanyId());
        ccc.setVerified(VerifyEnum.YES.getValue());
        ccc.setNotPassCause("");
        ccc.setCreateType(OperatorTypeEnum.EMPLOYEE.getValue());
        ccc.setCreateId(option.getOperationId());
        ccc.setCreateTime(now);
        ccc.setUpdateType(OperatorTypeEnum.EMPLOYEE.getValue());
        ccc.setUpdateId(option.getOperationId());
        ccc.setUpdateTime(now);
        ccc.setUserId(option.getOperationId());
        ccc.setVerifyId(option.getOperationId());
        ccc.setVerifyTime(now);
        // 新增关联信息
        associateMapper.insertSelective(ccc);
    }

    /**
     * 重新生成证照的审批数据，每当关联有变化的时候应当调用此方法进行更新
     *
     * @param certificateId 证照ID
     */
    private void revalidateCertificateApproveData(Long certificateId) {
        //
        // 首先删除之前的证照审批数据
        log.debug("删除证照 [{}] 的审批数据", certificateId);
        approveMapper.deleteById(certificateId);


        //
        // 重新生成证照审批数据
        CompanyCertificateChemicalApproveDO approveData = approveGenerator.generateFromAssociatedCertificateIds(Collections.singletonList(certificateId))
                .stream()
                .findAny()
                .orElse(null);

        if (null != approveData) {
            log.debug("生成证照 [{}] 的审批数据", certificateId);
            this.approveMapper.insertSelective(approveData);
        } else {
            log.debug("不再生成证照 [{}] 的审批数据", certificateId);
        }
    }


    private void insertAssociates(List<CompanyCertificateChemicalDO> insertAssociates) {
        final int chunkSize = 50;
        final AtomicInteger counter = new AtomicInteger();
        insertAssociates.stream()
                .collect(Collectors.groupingBy(it -> counter.getAndIncrement() / chunkSize))
                .values()
                .forEach(associateMapper::insertMultiple);
    }

    private List<Long> applyResultsAsChemicalIds(Long companyId,
                                                 Long certificateId,
                                                 List<AssociateChemicalDetectResultReqDTO> associateChemicalDetectResults,
                                                 List<AssociateChemicalResultRspDTO> results) {
        Map<Integer, AssociateChemicalResultRspDTO> resultIndexMap = IntStream.range(0, results.size())
                .mapToObj(i -> new Object[]{i, results.get(i)})
                .collect(Collectors.toMap(
                        e -> (Integer) e[0],
                        e -> (AssociateChemicalResultRspDTO) e[1]));

        //
        // 探测结果
        List<ValueWithIndex<AssociateChemicalDetectResultReqDTO>> detectedWithIndex =
                detectChemicalsAsIndexedList(associateChemicalDetectResults);

        //
        // 判断是否不是管制品，把不是管制品的直接设置为失败
        // 并且把管制品收集起来
        List<ValueWithIndex<AssociateChemicalDetectResultReqDTO>> restrictedChemicals = detectedWithIndex.stream()
                .map(e -> {
                    if (!e.getValue().isRestricted()) {
                        resultIndexMap
                                .get(e.getIndex())
                                .setResult(AssociateChemicalResultEnum.NOT_DANGER_CHEMICAL);
                        return null;
                    }
                    return e;
                })
                .filter(Objects::nonNull)
                .collect(Collectors.toList());


        //
        // 重新关联列表
        final List<Long> associateChemicalIds = new ArrayList<>();

        //
        // 按照化合物ID分组
        Map<Long, List<ValueWithIndex<AssociateChemicalDetectResultReqDTO>>> chemicalIdIndexed =
                restrictedChemicals.stream()
                        .collect(Collectors.groupingBy(e -> e.getValue().getChemicalId()));

        //
        // 查询是否已经关联
        List<Long> chemicalIds = restrictedChemicals.stream()
                .map(e -> e.getValue().getChemicalId())
                .collect(Collectors.toList());
        List<CompanyCertificateChemicalDO> associates = chemicalIds.isEmpty()
                ? Collections.emptyList()
                : associateMapper.listByCompanyIdCertificateIdAndChemicalIds(companyId, certificateId, chemicalIds);

        //
        // 判断是否已经存在关联，已经关联的直接设置结果
        for (CompanyCertificateChemicalDO associated : associates) {
            List<ValueWithIndex<AssociateChemicalDetectResultReqDTO>> existChemicals = chemicalIdIndexed.get(associated.getChemicalId());
            if (!CollectionUtils.isEmpty(existChemicals)) {
                existChemicals.forEach(item -> {
                    AssociateChemicalResultRspDTO result = resultIndexMap.get(item.getIndex());
                    switch (VerifyEnum.fromValue(associated.getVerified())) {
                        case NO:
                            // 未通过，需要重新插入新的关联
                            associateChemicalIds.add(associated.getChemicalId());
                            result.setResult(AssociateChemicalResultEnum.WAITING_VERIFY);
                            break;
                        case ING:
                            // 审核中，直接设置结果
                            result.setResult(AssociateChemicalResultEnum.WAITING_VERIFY);
                            break;
                        case YES:
                            // 审核通过，直接设置结果
                            result.setResult(AssociateChemicalResultEnum.ALREADY_ASSOCIATED);
                            break;
                    }
                });
            }
            chemicalIdIndexed.remove(associated.getChemicalId());
        }

        //
        // 未关联的需要插入关联
        chemicalIdIndexed.forEach((chemicalId, detectList) -> {
            associateChemicalIds.add(chemicalId);
            detectList.forEach(e -> resultIndexMap.get(e.getIndex())
                    .setResult(AssociateChemicalResultEnum.WAITING_VERIFY));
        });


        return associateChemicalIds;
    }

    private List<ValueWithIndex<AssociateChemicalDetectResultReqDTO>> detectChemicalsAsIndexedList(
            List<AssociateChemicalDetectResultReqDTO> associateChemicalDetectResults) {
        return IntStream.range(0, associateChemicalDetectResults.size())
                .filter(i -> Objects.nonNull(associateChemicalDetectResults.get(i)))
                .mapToObj(i -> new ValueWithIndex<>(associateChemicalDetectResults.get(i), i))
                .collect(Collectors.toList());
    }


    @Value
    private static class ValueWithIndex<T> {
        T value;
        int index;
    }

    @Override
    public List<CompanyCertificateChemicalPageItemRspDTO> selectByIds(List<Long> ids) {
        return associateMapper.listByIds(ids).stream().map(item -> {
            return BeanUtil.copyProperties(item, CompanyCertificateChemicalPageItemRspDTO.class);
        }).collect(Collectors.toList());
    }

    @Override
    public void ineffectiveByChemicalAndCompanyId(long certificateId, List<Long> chemicalIds, long companyId) {
        if (CollUtil.isNotEmpty(chemicalIds)) {
            this.update(new LambdaUpdateWrapper<CompanyCertificateChemicalDO>()
                    .set(CompanyCertificateChemicalDO::getIsEffective, System.currentTimeMillis() / 1000)
                    .eq(CompanyCertificateChemicalDO::getCertificateId, certificateId)
                    .in(CompanyCertificateChemicalDO::getChemicalId, chemicalIds)
                    .eq(CompanyCertificateChemicalDO::getCompanyId, companyId)
                    .eq(CompanyCertificateChemicalDO::getDeleted, 0)
                    .eq(CompanyCertificateChemicalDO::getIsEffective, 1));
        }
    }
}
